﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading.Tasks;
using EchoPlanNote.IRepository;

namespace EchoPlanNote.Repository
{
    public class BaseRepository<TEntity> : IBaseRepository<TEntity> where TEntity : class
    {
        // 数据上下文容器 使用线程内唯一 线程销毁 数据上下文也销毁
        BaseDBContext dbContext
        {
            get
            {
                // 先从线程中查找ef对象 没有则创建
                var db = CallContext.GetData("BaseDBContext");
                if (db == null)
                {
                    db = new BaseDBContext();
                    CallContext.SetData("BaseDBContext", db);
                }

                return db as BaseDBContext;
            }
        }

        DbSet<TEntity> _dbset;
        public BaseRepository()
        {
            _dbset = dbContext.Set<TEntity>();
        }

        #region 查询方法
        /// <summary>
        /// 根据labmda表达式进行查询
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns>满足条件的数据集合</returns>
        public List<TEntity> QueryWhere(Expression<Func<TEntity, bool>> where)
        {
            return _dbset.Where(where).ToList();
        }

        /// <summary>
        /// 连表操作
        /// </summary>
        /// <param name="where"></param>
        /// <param name="tableNames"></param>
        /// <returns></returns>
        public List<TEntity> QueryJoin(Expression<Func<TEntity, bool>> where, string[] tableNames)
        {
            if (tableNames == null || tableNames.Any() == false)
            {
                throw new Exception("连表操作的表名称至少要有一个");
            }

            DbQuery<TEntity> query = _dbset;

            foreach (var tablename in tableNames)
            {
                query = query.Include(tablename);
            }

            return query.Where(where).ToList();

            //return _dbset.Include("A").Include("B")
        }

        /// <summary>
        /// 按照条件查询出数据以后，根据外部指定的字段进行升序排列
        /// </summary>
        /// <typeparam name="TKey">表示从TEntity中获取的属性类型</typeparam>
        /// <param name="where">条件</param>
        /// <param name="order">排序lambda表达式</param>
        /// <returns></returns>
        public List<TEntity> QueryOrderBy<TKey>(Expression<Func<TEntity, bool>> where, Expression<Func<TEntity, TKey>> order)
        {
            return _dbset.Where(where).OrderBy(order).ToList();
        }

        /// <summary>
        /// 按照条件查询出数据以后，根据外部指定的字段进行倒序排列
        /// </summary>
        /// <typeparam name="TKey">表示从TEntity中获取的属性类型</typeparam>
        /// <param name="where">条件</param>
        /// <param name="order">排序lambda表达式</param>
        /// <returns></returns>
        public List<TEntity> QueryOrderByDescending<TKey>(Expression<Func<TEntity, bool>> where, Expression<Func<TEntity, TKey>> order)
        {
            return _dbset.Where(where).OrderByDescending(order).ToList();
        }

        /// <summary>
        /// 分页方法
        /// </summary>
        /// <typeparam name="TKey">要指定的排序属性名称 Tentity.property</typeparam>
        /// <param name="pageindex">分页页码</param>
        /// <param name="pagesize">页容量</param>
        /// <param name="rowcount">总行数</param>
        /// <param name="order">排序lambda表达式</param>
        /// <param name="where">查询条件lambda表达式</param>
        /// <returns></returns>
        public List<TEntity> QueryByPage<TKey>(int pageindex, int pagesize, out int rowcount, Expression<Func<TEntity, TKey>> order, Expression<Func<TEntity, bool>> where)
        {
            //1.0 计算当前分页要跳过的数据行数
            int skipCount = (pageindex - 1) * pagesize;

            //2.0 获取当前满足条件的所有数据总条数
            rowcount = _dbset.Count(where);

            //3.0 获取分页数据
            return _dbset.Where(where).OrderByDescending(order).Skip(skipCount).Take(pagesize).ToList();
        }
        #endregion

        #region 编辑方法
        public void Edit(TEntity model)
        {
            if (model == null)
            {
                throw new Exception("实体不能为空");
            }
            //2.0 将model追击到EF容器
            DbEntityEntry entry = dbContext.Entry(model);
            entry.State = EntityState.Modified;
        }
        #endregion

        #region 删除相关方法

        public void Delete(TEntity model, bool isadded)
        {
            //(!isadded)表示当前model没有追加到EF容器中
            if (!isadded)
            {
                _dbset.Attach(model);
            }
            _dbset.Remove(model);
        }


        public void DeleteEntities(List<TEntity> entities)
        {
            if (entities != null)
            {
                foreach (var item in entities)
                {
                    Delete(item, true);
                }
            }
        }

        #endregion

        #region 新增相关方法

        public void Add(TEntity model)
        {
            _dbset.Add(model);
        }

        #endregion

        #region 使用原始sql语句调用（包括存储过程）
        public List<TResult> RunProcedure<TResult>(string sql, params object[] parameters)
        {
            return dbContext.Database.SqlQuery<TResult>(sql, parameters).ToList<TResult>();
        }
        #endregion

        #region 统一提交

        public int SaveChanges()
        {
            return dbContext.SaveChanges();
        }

        #endregion
    }
}
